package com.htfyun.serialport.uartservo.AX12_ServoUpdate;

import com.htfyun.serialport.core.OnSerialPortDataListener;
import com.htfyun.serialport.core.SerialPortManager;
import com.htfyun.serialport.uartservo.IServoCommand;
import com.htfyun.serialport.uartservo.IServoReadDataAnalyze;
import com.htfyun.serialport.utils.SerialDebugLog;
import com.htfyun.serialport.utils.UsefulUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;


public class AX12Update_Control implements OnSerialPortDataListener {
    private final static boolean DEBUG = true;

    private final static byte AX12UPDATE_SERVO_ID = 1;//(byte)0xfe;

    private static AX12Update_Control instance = null;

    private UUID uuidToken = null;

    protected IServoCommand servoCommand;
    protected IServoReadDataAnalyze readDataAnalyze;

    private List<OnUpdateServoListener> servoListenerList = new CopyOnWriteArrayList<>();


    private AX12Update_Control(IServoCommand command, IServoReadDataAnalyze analyze) {
        this.servoCommand = command;
        this.readDataAnalyze = analyze;

        servoCommand.setId(new byte[]{AX12UPDATE_SERVO_ID});

        SerialPortManager.INSTANCE.setIntervalBetweenWriteUART_ms(2);

    }


    public static AX12Update_Control getInstance(){
        if (instance == null) {

            synchronized (AX12Update_Control.class) {
                if (instance == null) {
                    instance = new AX12Update_Control(new AX12Update_ServoCommand(), new AX12Update_ServoReadDataAnalyze());
                }
            }
        }
        return instance;
    }

    public void release() {
        servoListenerList.clear();
        SerialPortManager.INSTANCE.unregisterSerialPortDataListener(uuidToken);
        uuidToken = null;
    }

    public void sendCmdHandshakeWithBinTotalSize(int binSize) {

        // ff ff 01 02 64 98 会让舵机进入loader状态.
        //writeServo(new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0x01, (byte) 0x02, (byte) 0x64, (byte) 0x98});

        ByteBuffer byteBuffer = ByteBuffer.allocate(4);
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
        byteBuffer.putInt(binSize);

        servoControl(AX12Update_instructionAttr.handshake, byteBuffer.array());
    }

    public void sendCmdEraser() {

        servoControl(AX12Update_instructionAttr.eraser, null);

//        writeServo(new byte[]{(byte) 0xfd, (byte) 0xfd, 0x01, 0x08, 0x00, (byte) 0x97, 0x02, (byte) 0x5d});

    }

    public void sendBinData(int writingDataLength, byte[] binData) {

        ByteBuffer byteBuffer = ByteBuffer.allocate(4 + binData.length);
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
        byteBuffer.putInt(writingDataLength);
        byteBuffer.put(binData);

        servoControl(AX12Update_instructionAttr.write, byteBuffer.array());
    }

    private void servoControl(AX12Update_instructionAttr attr, byte[] data) {

        servoCommand.setInstruction(attr.getUpdateInstruction());
        servoCommand.setParameters(data);

        writeServo(servoCommand.buildForCommand());

    }

    public void registerUpdateServoListener(OnUpdateServoListener listener) {
        if (!servoListenerList.contains(listener)) {
            servoListenerList.add(listener);
        }
    }

    public void unregisterUpdateServoListener(OnUpdateServoListener listener) {
        servoListenerList.remove(listener);
    }
    /////////////////////////////////////////////////////
    /////////////////////////////////////////////////////
    private void onServoListenerAction(AX12Update_instructionAttr instructionAttr,
                                         int wroteDataLength) {

        if (servoListenerList.isEmpty()) {
            return;
        }

        for (OnUpdateServoListener listener : servoListenerList) {
            listener.onUpdateServoListener(instructionAttr, wroteDataLength);
        }

    }

    private void writeServo(byte[] bytes) {
        if (uuidToken == null) {
            uuidToken = SerialPortManager.INSTANCE.registerSerialPortDataListener(this);
        }
        SerialPortManager.INSTANCE.writeSerialPort(uuidToken, bytes);
    }


    @Override
    public void onWriteData(UUID uuidToken, ByteBuffer wByteBuffer) {
        if (DEBUG)
            SerialDebugLog.e("onWriteData = " + UsefulUtil.toHexString(wByteBuffer.array()));

    }

    @SuppressWarnings("unchecked")
    @Override
    public void onReadData(UUID uuidToken, byte[] readData, int len) {

        if (!uuidToken.equals(this.uuidToken)) {
            return;
        }

        if (len <= 0) {
            return;
        }

        if (readData == null || readData.length < len) {
            return;
        }

        if (DEBUG)
            SerialDebugLog.e("readData = " + UsefulUtil.toHexString(readData, len));

        List<AX12Update_ReceivedSerialPacket> packetList = readDataAnalyze.analyzeReadData(readData, len);

        if (packetList == null || packetList.isEmpty()) {
            return;
        }

        for (AX12Update_ReceivedSerialPacket packet : packetList) {

            SerialDebugLog.e("packet = " + packet);

            doActionByAnalyzeReadPacket(packet);
        }

    }

    private void doActionByAnalyzeReadPacket(AX12Update_ReceivedSerialPacket rPacket) {

        if (rPacket.isValid() && rPacket.getId() != AX12UPDATE_SERVO_ID) {
            return;
        }

        onServoListenerAction(rPacket.getInstructionAttr(), rPacket.getWroteDataLength());

    }
}
